package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Node;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.MenuVo;
import com.zzyl.vo.ResourceVo;
import com.zzyl.vo.TreeItemVo;
import com.zzyl.vo.TreeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description ResourceServiceImpl
 * @Author luohai
 * @Date 2024-10-23
 */
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 资源列表
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstant.RESOURCE_LIST,key = "#resourceDto.hashCode()")
    public List<ResourceVo> resourceList(ResourceDto resourceDto) {
        return resourceMapper.findByCondition(resourceDto);
    }

    /**
     * @param resourceDto 资源对象
     * @return 资源树形
     */
    @Override
    @Cacheable(value = CacheConstant.RESOURCE_TREE,key = "#resourceDto.hashCode()")
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        //1.查询所有节点对象
        //构建封装查询条件：查询菜单、正常状态、根节点去掉末位0（查后代）
        resourceDto.setResourceType(SuperConstant.MENU);
        resourceDto.setDataState(SuperConstant.DATA_STATE_0);
        resourceDto.setParentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID));
        //执行查询得到所有菜单列表
        List<ResourceVo> resourceList = resourceMapper.findByCondition(resourceDto);
        //判断菜单列表是否为空，抛出异常“没有菜单”
        if (BeanUtil.isEmpty(resourceList)) {
            throw new RuntimeException("菜单不存在");
        }
        //2.构建根节点子节点集合List<TreeItemVo>树形列表数据
        //构建TreeNodeConfig，将name别名改为label
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setNameKey("label");
        //利用hutool属性构建工具TreeUtil获取树形结构数据 List<Tree<String>>, Tree是hutool工具类底层就是map
        //语法：List<Tree<String>> TreeUtil.build(List<T>,E,TreeNodeConfig,NodeParser<T,E>)
        //     List<T> 设置所有节点列表，这里传递resourceList
        //     E, 根节点编号
        //     TreeNodeConfig, 节点配置对象，可以给节点设置属性别名
        //     NodeParser<T,E> 构建属性函数，传入2个参数，第一个参数是List<T>集合的每个元素，第二个参数是构建树形节点对象
        List<Tree<String>> treeList = TreeUtil.build(resourceList, SuperConstant.ROOT_PARENT_ID, treeNodeConfig, (resource, treeNode) -> {
            treeNode.setParentId(resource.getParentResourceNo());
            treeNode.setId(resource.getResourceNo());
            treeNode.setName(resource.getResourceName());
        });
        //将List<Tree<String>>转换为根节点子节点集合List<TreeItemVo>
        List<TreeItemVo> children = BeanUtil.copyToList(treeList, TreeItemVo.class);

        //3.构建根节点智慧养老院对象TreeItemVo对象
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(SuperConstant.ROOT_PARENT_ID)
                .label("智慧养老院")
                .children(children)
                .build();

        //4.构建整棵树TreeVo对象，返回
        ArrayList<TreeItemVo> items = new ArrayList<>();
        items.add(treeItemVo);

        return TreeVo.builder()
                .items(items)
                .build();
    }

    /**
     * 资源添加
     * @param resourceDto
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
    })
    public Boolean createResource(ResourceDto resourceDto) {
        //1.将resourceDto转换为resource对象
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //2.同步父资源状态
        //2.1 根据父资源编号查询对应资源对象
        Resource parentResource=resourceMapper.findByParentResourceNo(resource.getParentResourceNo());
        //2.2 将父资源状态封装给resource对象
        resource.setDataState(parentResource.getDataState());
        //3.生成子资源编号封装到resource对象
        String resourceNo=createResourceNo(resource);
        resource.setResourceNo(resourceNo);
        //4.调用mapper插入资源到数据库
        resourceMapper.insertSelective(resource);
        //5.返回成功
        return true;
    }

    /**
     * 资源修改
     * @param resourceDto
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
    })
    public Boolean resourceModification(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        if (NoProcessing.processString(resource.getParentResourceNo()).length()/3>4){
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        String resourceNo = createResourceNo(resource);
        resource.setResourceNo(resourceNo);
        resourceMapper.resourceModification(resource);
        return true;
    }

    /**
     * 启用禁用
     * @param resourceDto
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
    })
    public Boolean enableDisable(ResourceDto resourceDto) {
        resourceMapper.enableDisable(resourceDto);
        return true;
    }

    /**
     * 删除菜单
     * @param resourceNo
     * @return
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE,allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST,allEntries = true),
    })
    public void deleteResource(String resourceNo) {
        ResourceDto resourceDto = ResourceDto.builder().resourceNo(NoProcessing.processString(resourceNo)).build();
        List<ResourceVo> resourceVoList = resourceMapper.findByCondition(resourceDto);
        List<ResourceVo> list = resourceVoList.stream().filter(s -> (s.getDataState()).equals(1)).collect(Collectors.toList());
        if (list != null){
            throw new BaseException(BasicEnum.CANNOT_PLACE_ORDER_DUE_ELDER_ALREADY_RETREATED);
        }else {
            resourceMapper.deleteResource(resourceNo);
        }

    }

    /**
     * 获取用户的树形菜单
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //获取用户的所有菜单列表集合list<MenuVo>
        List<MenuVo> menuVos=resourceMapper.findMenuListByUserId(userId);
        //2.使用hutool工具构建树形的list<Tree<string>>
        List<Tree<String>> treeList = TreeUtil.build(
                menuVos,
                SuperConstant.ROOT_PARENT_ID,
                (menu, treeNo) -> {
                    //默认生成每个节点属性：id,name,children,扩展属性：path,redirect,meta
                    treeNo.setId(menu.getResourceNo());
                    treeNo.setParentId(menu.getParentResourceNo());
                    treeNo.setName(menu.getName());
                    treeNo.put("path", menu.getPath());
                    treeNo.put("redirect", "/" + menu.getName());
                    treeNo.put("meta", menu.getMeta());
                });
        //3.List<Tree<String>> 转换为树形List<MenuVo>
        List<MenuVo> menuVoList=BeanUtil.copyToList(treeList, MenuVo.class);
        //返回数据
        return menuVoList;
    }


    /**
     * 生成资源编号
     * @param resource
     * @return
     */
    private String createResourceNo(Resource resource) {
        //1.判断如果添加的是菜单类型，并且要判断父资源编号层级不能超过12位（4层，2级菜单），否则抛出异常
        if (resource.getResourceType().equals(SuperConstant.MENU) &&
        NoProcessing.processString(resource.getParentResourceNo()).length()/3>4){
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //2.判断父资源是否有子资源
        //2.1 根据父节点编号查找子节点列表数据
        ResourceDto resourceDto = ResourceDto.builder().parentResourceNo(resource.getParentResourceNo()).build();
        List<ResourceVo> resourceVoList = resourceMapper.findByCondition(resourceDto);
        //2.2 判断子节点列表数据是否有数据
        if (ObjectUtil.isEmpty(resourceVoList)){
            //2.2.1 没有
            //调用工具类NoProcessing.createNo(父节点编号,false)生成编号返回
            return NoProcessing.createNo(resource.getParentResourceNo(),false);
        }else {
            //2.2.2 有
            //抽取出来所有子节点编号
            List<String> resourceNoList = resourceVoList.stream().map(ResourceVo::getResourceNo).collect(Collectors.toList());
            //获取最大子节点编号
            Long maxResourceNo = resourceNoList.stream().map(i -> Long.valueOf(i)).max(Comparator.comparing(i -> i)).get();
            //调用工具类NoProcessing.createNo(传递最大子节点编号,true)生成编号返回
            return NoProcessing.createNo(maxResourceNo.toString(),true);
        }
    }

}
